This notebook performs Exploratory Data Analysis on the motor vehicle crashes data aggregated with the ACS data

LOAD DATA

df <- read_csv("../data/processed/acs_mvc_combined_2018_2023.csv")
glimpse(df)
Rows: 13,984
Columns: 63
$ geoid                    <dbl> 3.6005e+10, 3.6005e+10, 3.6005e+10, 3.6005…
$ year                     <dbl> 2018, 2019, 2020, 2021, 2022, 2023, 2018, …
$ total_population         <dbl> 47900.000, 46630.000, 44881.000, 45523.000…
$ pct_male_population      <dbl> 13.576200, 13.607120, 13.691763, 13.568965…
$ pct_female_population    <dbl> 1.2045929, 1.1130174, 1.0137920, 1.0631988…
$ pct_white_population     <dbl> 3.7014614, 4.7887626, 5.7039727, 5.8871340…
$ pct_black_population     <dbl> 8.849687, 8.200729, 7.666941, 7.187576, 6.…
$ pct_asian_population     <dbl> 0.26096033, 0.38816213, 0.38100755, 0.3888…
$ pct_hispanic_population  <dbl> 4.862213, 5.161913, 5.158085, 4.758034, 3.…
$ pct_foreign_born         <dbl> 2.206681, 2.365430, 2.319467, 2.220855, 1.…
$ pct_age_under_18         <dbl> 0.3569937, 0.2208878, 0.2161271, 0.2152758…
$ pct_age_18_34            <dbl> 0.000000, 0.000000, 0.000000, 0.000000, 0.…
$ pct_age_35_64            <dbl> 0.000000, 0.000000, 0.000000, 0.000000, 0.…
$ pct_age_65_plus          <dbl> 0.000000, 0.000000, 0.000000, 0.000000, 0.…
$ median_income            <dbl> 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, …
$ pct_income_under_25k     <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_income_25k_75k       <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_income_75k_plus      <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_below_poverty        <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_above_poverty        <dbl> 0.000000, 0.000000, 0.000000, 0.000000, 0.…
$ poverty_rate             <dbl> NA, NA, NA, NA, NA, NA, 22.633201, 22.4404…
$ median_gross_rent        <dbl> 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.…
$ pct_owner_occupied       <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_renter_occupied      <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_no_vehicle           <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_one_vehicle          <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_two_plus_vehicles    <dbl> 0.00000000, 0.00000000, 0.00000000, 0.0000…
$ pct_less_than_hs         <dbl> 6.3924843, 6.0261634, 5.7017446, 5.6608747…
$ pct_hs_diploma           <dbl> 2.0229645, 2.7364358, 3.0547448, 3.4619862…
$ pct_some_college         <dbl> 1.2526096, 1.1237401, 1.0405294, 0.9797245…
$ pct_associates_degree    <dbl> 0.1691023, 0.1737079, 0.2339520, 0.2723898…
$ pct_bachelors_degree     <dbl> 0.14822547, 0.15440703, 0.18938972, 0.2372…
$ pct_graduate_degree      <dbl> 0.01670146, 0.01930088, 0.04233417, 0.0527…
$ pct_in_labor_force       <dbl> 0.000000, 0.000000, 0.000000, 0.000000, 0.…
$ pct_employed             <dbl> 0.000000, 0.000000, 0.000000, 0.000000, 0.…
$ pct_unemployed           <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_not_in_labor_force   <dbl> 14.780793, 14.720137, 14.705555, 14.632164…
$ unemployment_rate        <dbl> NA, NA, NA, NA, NA, NA, 15.750133, 13.4787…
$ pct_commute_short        <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_commute_medium       <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_commute_long         <dbl> 0.000000, 0.000000, 0.000000, 0.000000, 0.…
$ pct_drive_alone          <dbl> 0.000000, 0.000000, 0.000000, 0.000000, 0.…
$ pct_carpool              <dbl> 0.00000000, 0.00000000, 0.00000000, 0.0000…
$ pct_public_transit       <dbl> 0.000000, 0.000000, 0.000000, 0.000000, 0.…
$ pct_walk                 <dbl> 0.00000000, 0.00000000, 0.00000000, 0.0000…
$ pct_bike                 <dbl> 0.00000000, 0.00000000, 0.00000000, 0.0000…
$ pct_work_from_home       <dbl> 0.00000000, 0.00000000, 0.00000000, 0.0000…
$ total_crashes            <dbl> 2, 4, 0, 0, 0, 0, 43, 30, 31, 30, 17, 20, …
$ persons_injured          <dbl> 1, 2, 0, 0, 0, 0, 11, 8, 12, 12, 10, 10, 1…
$ persons_killed           <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, …
$ pedestrians_injured      <dbl> 0, 0, 0, 0, 0, 0, 2, 2, 3, 2, 4, 1, 3, 0, …
$ pedestrians_killed       <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
$ cyclists_injured         <dbl> 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 1, 1, 2, …
$ cyclists_killed          <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
$ motorists_injured        <dbl> 1, 2, 0, 0, 0, 0, 9, 4, 8, 10, 4, 8, 6, 16…
$ motorists_killed         <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, …
$ crash_rate_per_1000      <dbl> 0.04175365, 0.08578169, 0.00000000, 0.0000…
$ injury_rate_per_1000     <dbl> 0.02087683, 0.04289084, 0.00000000, 0.0000…
$ fatality_rate_per_1000   <dbl> 0.00000000, 0.00000000, 0.00000000, 0.0000…
$ pedestrian_rate_per_1000 <dbl> 0.00000000, 0.00000000, 0.00000000, 0.0000…
$ cyclist_rate_per_1000    <dbl> 0.00000000, 0.00000000, 0.00000000, 0.0000…
$ motorist_rate_per_1000   <dbl> 0.02087683, 0.04289084, 0.00000000, 0.0000…
$ injury_fatality_ratio    <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…

CONVERT DATA TYPES

df <- df %>%
  mutate(
    geoid = as.character(geoid),
    year = as.integer(year),
    total_population = as.integer(total_population),
    total_crashes = as.integer(total_crashes),
    persons_injured = as.integer(persons_injured),
    persons_killed = as.integer(persons_killed),
    pedestrians_injured = as.integer(pedestrians_injured),
    pedestrians_killed = as.integer(pedestrians_killed),
    cyclists_injured = as.integer(cyclists_injured),
    cyclists_killed = as.integer(cyclists_killed),
    motorists_injured = as.integer(motorists_injured),
    motorists_killed = as.integer(motorists_killed)
  )
glimpse(df)
Rows: 13,984
Columns: 63
$ geoid                    <chr> "36005000100", "36005000100", "36005000100…
$ year                     <int> 2018, 2019, 2020, 2021, 2022, 2023, 2018, …
$ total_population         <int> 47900, 46630, 44881, 45523, 30541, 24345, …
$ pct_male_population      <dbl> 13.576200, 13.607120, 13.691763, 13.568965…
$ pct_female_population    <dbl> 1.2045929, 1.1130174, 1.0137920, 1.0631988…
$ pct_white_population     <dbl> 3.7014614, 4.7887626, 5.7039727, 5.8871340…
$ pct_black_population     <dbl> 8.849687, 8.200729, 7.666941, 7.187576, 6.…
$ pct_asian_population     <dbl> 0.26096033, 0.38816213, 0.38100755, 0.3888…
$ pct_hispanic_population  <dbl> 4.862213, 5.161913, 5.158085, 4.758034, 3.…
$ pct_foreign_born         <dbl> 2.206681, 2.365430, 2.319467, 2.220855, 1.…
$ pct_age_under_18         <dbl> 0.3569937, 0.2208878, 0.2161271, 0.2152758…
$ pct_age_18_34            <dbl> 0.000000, 0.000000, 0.000000, 0.000000, 0.…
$ pct_age_35_64            <dbl> 0.000000, 0.000000, 0.000000, 0.000000, 0.…
$ pct_age_65_plus          <dbl> 0.000000, 0.000000, 0.000000, 0.000000, 0.…
$ median_income            <dbl> 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, …
$ pct_income_under_25k     <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_income_25k_75k       <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_income_75k_plus      <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_below_poverty        <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_above_poverty        <dbl> 0.000000, 0.000000, 0.000000, 0.000000, 0.…
$ poverty_rate             <dbl> NA, NA, NA, NA, NA, NA, 22.633201, 22.4404…
$ median_gross_rent        <dbl> 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.…
$ pct_owner_occupied       <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_renter_occupied      <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_no_vehicle           <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_one_vehicle          <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_two_plus_vehicles    <dbl> 0.00000000, 0.00000000, 0.00000000, 0.0000…
$ pct_less_than_hs         <dbl> 6.3924843, 6.0261634, 5.7017446, 5.6608747…
$ pct_hs_diploma           <dbl> 2.0229645, 2.7364358, 3.0547448, 3.4619862…
$ pct_some_college         <dbl> 1.2526096, 1.1237401, 1.0405294, 0.9797245…
$ pct_associates_degree    <dbl> 0.1691023, 0.1737079, 0.2339520, 0.2723898…
$ pct_bachelors_degree     <dbl> 0.14822547, 0.15440703, 0.18938972, 0.2372…
$ pct_graduate_degree      <dbl> 0.01670146, 0.01930088, 0.04233417, 0.0527…
$ pct_in_labor_force       <dbl> 0.000000, 0.000000, 0.000000, 0.000000, 0.…
$ pct_employed             <dbl> 0.000000, 0.000000, 0.000000, 0.000000, 0.…
$ pct_unemployed           <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_not_in_labor_force   <dbl> 14.780793, 14.720137, 14.705555, 14.632164…
$ unemployment_rate        <dbl> NA, NA, NA, NA, NA, NA, 15.750133, 13.4787…
$ pct_commute_short        <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_commute_medium       <dbl> 0.0000000, 0.0000000, 0.0000000, 0.0000000…
$ pct_commute_long         <dbl> 0.000000, 0.000000, 0.000000, 0.000000, 0.…
$ pct_drive_alone          <dbl> 0.000000, 0.000000, 0.000000, 0.000000, 0.…
$ pct_carpool              <dbl> 0.00000000, 0.00000000, 0.00000000, 0.0000…
$ pct_public_transit       <dbl> 0.000000, 0.000000, 0.000000, 0.000000, 0.…
$ pct_walk                 <dbl> 0.00000000, 0.00000000, 0.00000000, 0.0000…
$ pct_bike                 <dbl> 0.00000000, 0.00000000, 0.00000000, 0.0000…
$ pct_work_from_home       <dbl> 0.00000000, 0.00000000, 0.00000000, 0.0000…
$ total_crashes            <int> 2, 4, 0, 0, 0, 0, 43, 30, 31, 30, 17, 20, …
$ persons_injured          <int> 1, 2, 0, 0, 0, 0, 11, 8, 12, 12, 10, 10, 1…
$ persons_killed           <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, …
$ pedestrians_injured      <int> 0, 0, 0, 0, 0, 0, 2, 2, 3, 2, 4, 1, 3, 0, …
$ pedestrians_killed       <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
$ cyclists_injured         <int> 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 1, 1, 2, …
$ cyclists_killed          <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
$ motorists_injured        <int> 1, 2, 0, 0, 0, 0, 9, 4, 8, 10, 4, 8, 6, 16…
$ motorists_killed         <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, …
$ crash_rate_per_1000      <dbl> 0.04175365, 0.08578169, 0.00000000, 0.0000…
$ injury_rate_per_1000     <dbl> 0.02087683, 0.04289084, 0.00000000, 0.0000…
$ fatality_rate_per_1000   <dbl> 0.00000000, 0.00000000, 0.00000000, 0.0000…
$ pedestrian_rate_per_1000 <dbl> 0.00000000, 0.00000000, 0.00000000, 0.0000…
$ cyclist_rate_per_1000    <dbl> 0.00000000, 0.00000000, 0.00000000, 0.0000…
$ motorist_rate_per_1000   <dbl> 0.02087683, 0.04289084, 0.00000000, 0.0000…
$ injury_fatality_ratio    <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…

DATA QUALITY CHECKS

# Visualize missingness
vis_miss(df)


# Count NA values per column
colSums(is.na(df))
                   geoid                     year         total_population 
                       0                        0                        0 
     pct_male_population    pct_female_population     pct_white_population 
                     426                      426                      426 
    pct_black_population     pct_asian_population  pct_hispanic_population 
                     426                      426                      426 
        pct_foreign_born         pct_age_under_18            pct_age_18_34 
                     426                      426                      426 
           pct_age_35_64          pct_age_65_plus            median_income 
                     426                      426                        0 
    pct_income_under_25k       pct_income_25k_75k      pct_income_75k_plus 
                     426                      426                      426 
       pct_below_poverty        pct_above_poverty             poverty_rate 
                     426                      426                      455 
       median_gross_rent       pct_owner_occupied      pct_renter_occupied 
                       0                      426                      426 
          pct_no_vehicle          pct_one_vehicle    pct_two_plus_vehicles 
                     426                      426                      426 
        pct_less_than_hs           pct_hs_diploma         pct_some_college 
                     426                      426                      426 
   pct_associates_degree     pct_bachelors_degree      pct_graduate_degree 
                     426                      426                      426 
      pct_in_labor_force             pct_employed           pct_unemployed 
                     426                      426                      426 
  pct_not_in_labor_force        unemployment_rate        pct_commute_short 
                     426                      464                      426 
      pct_commute_medium         pct_commute_long          pct_drive_alone 
                     426                      426                      426 
             pct_carpool       pct_public_transit                 pct_walk 
                     426                      426                      426 
                pct_bike       pct_work_from_home            total_crashes 
                     426                      426                        0 
         persons_injured           persons_killed      pedestrians_injured 
                       0                        0                        0 
      pedestrians_killed         cyclists_injured          cyclists_killed 
                       0                        0                        0 
       motorists_injured         motorists_killed      crash_rate_per_1000 
                       0                        0                      426 
    injury_rate_per_1000   fatality_rate_per_1000 pedestrian_rate_per_1000 
                     426                      426                      426 
   cyclist_rate_per_1000   motorist_rate_per_1000    injury_fatality_ratio 
                     426                      426                    12721 

Identify and remove 426 rows with extensive missingness

df$na_rate <- rowMeans(is.na(df))

# Filter out rows with high missingness
df <- df %>%
    filter(rowMeans(is.na(.)) <= 0.05)

# Drop 29 rows with poverty_rate NA and/or 38 unemployment_rate NA values
df <- df %>%
    drop_na(c(unemployment_rate, poverty_rate))

# Drop na_rate column
df <- df %>% select(-na_rate, -injury_fatality_ratio)

Second quality check

# Visualize missingness
vis_miss(df)

NO NA values!

Winsorization of extreme values

replace_top_99_with_median <- function(x) {
  # Ensure numeric
  if (!is.numeric(x)) stop("Column must be numeric.")
  
  # Calculate the 99th percentile and median
  upper_threshold <- quantile(x, 0.99, na.rm = TRUE)
  median_val <- median(x, na.rm = TRUE)
  
  # Replace values above the 99th percentile with the median
  x[x > upper_threshold] <- median_val
  return(x)
}

per_1000_vars <- grep("per_1000", names(df), value = TRUE)
df[per_1000_vars] <- lapply(df[per_1000_vars], replace_top_99_with_median)

Univariate Analysis

GROUP CORRELATED SOCIO-ECONOMIC VARIABLES

numeric_vars <- sapply(df, is.numeric)
cor_matrix <- cor(df[ , numeric_vars], 
                  use = "pairwise.complete.obs")

# Identify columns to drop (to reduce multicollinearity)
high_corr <- caret::findCorrelation(cor_matrix, cutoff = 0.8)
colnames(cor_matrix)[high_corr]
 [1] "pct_income_75k_plus"    "poverty_rate"          
 [3] "pct_below_poverty"      "pct_employed"          
 [5] "pct_no_vehicle"         "pct_drive_alone"       
 [7] "unemployment_rate"      "persons_injured"       
 [9] "motorist_rate_per_1000" "pct_female_population" 
# Open a PNG device
png("../report/plots/pairwise_correlation_matrix.png", width = 1200, height = 1000, res = 300)

# Draw the plot
corrplot(cor_matrix, method = "color", type = "upper", tl.cex = 0.5)

# Close the device
dev.off()
null device 
          1 

DROP REDUNDANT VARIABLES

df <- df %>%
    select(-c(poverty_rate,
              pct_below_poverty,
              pct_above_poverty,
              pct_employed,
              pct_unemployed,
              pct_drive_alone))

ADD BOROUGHS

df <- df %>%
  mutate(
    borough = case_when(
      substr(geoid, 1, 5) == "36005" ~ "Bronx",
      substr(geoid, 1, 5) == "36047" ~ "Brooklyn",
      substr(geoid, 1, 5) == "36061" ~ "Manhattan",
      substr(geoid, 1, 5) == "36081" ~ "Queens",
      substr(geoid, 1, 5) == "36085" ~ "Staten Island",
      TRUE ~ "Unknown"
    )
  )

Export clean data

saveRDS(df, "../data/models/social-risk-crash-rate-data.rds")
LS0tCnRpdGxlOiAiMDEtRURBIFIgTm90ZWJvb2siCmF1dGhvcjogIkFKIFN0cmF1bWFuLVNjb3R0IgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KClRoaXMgbm90ZWJvb2sgcGVyZm9ybXMgRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyBvbiB0aGUgbW90b3IgdmVoaWNsZSBjcmFzaGVzIGRhdGEgYWdncmVnYXRlZCB3aXRoIHRoZSBBQ1MgZGF0YQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KEdHYWxseSkKbGlicmFyeShjb3JycGxvdCkKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KG5hbmlhcikKbGlicmFyeSh0bWFwKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShEZXNjVG9vbHMpCmBgYAoKIyMgTE9BRCBEQVRBCgpgYGB7ciBsb2FkLWRhdGF9CmRmIDwtIHJlYWRfY3N2KCIuLi9kYXRhL3Byb2Nlc3NlZC9hY3NfbXZjX2NvbWJpbmVkXzIwMThfMjAyMy5jc3YiKQpnbGltcHNlKGRmKQpgYGAKCiMjIENPTlZFUlQgREFUQSBUWVBFUwoKYGBge3IgY29udmVydC1kYXRhLXR5cGVzfQpkZiA8LSBkZiAlPiUKICBtdXRhdGUoCiAgICBnZW9pZCA9IGFzLmNoYXJhY3RlcihnZW9pZCksCiAgICB5ZWFyID0gYXMuaW50ZWdlcih5ZWFyKSwKICAgIHRvdGFsX3BvcHVsYXRpb24gPSBhcy5pbnRlZ2VyKHRvdGFsX3BvcHVsYXRpb24pLAogICAgdG90YWxfY3Jhc2hlcyA9IGFzLmludGVnZXIodG90YWxfY3Jhc2hlcyksCiAgICBwZXJzb25zX2luanVyZWQgPSBhcy5pbnRlZ2VyKHBlcnNvbnNfaW5qdXJlZCksCiAgICBwZXJzb25zX2tpbGxlZCA9IGFzLmludGVnZXIocGVyc29uc19raWxsZWQpLAogICAgcGVkZXN0cmlhbnNfaW5qdXJlZCA9IGFzLmludGVnZXIocGVkZXN0cmlhbnNfaW5qdXJlZCksCiAgICBwZWRlc3RyaWFuc19raWxsZWQgPSBhcy5pbnRlZ2VyKHBlZGVzdHJpYW5zX2tpbGxlZCksCiAgICBjeWNsaXN0c19pbmp1cmVkID0gYXMuaW50ZWdlcihjeWNsaXN0c19pbmp1cmVkKSwKICAgIGN5Y2xpc3RzX2tpbGxlZCA9IGFzLmludGVnZXIoY3ljbGlzdHNfa2lsbGVkKSwKICAgIG1vdG9yaXN0c19pbmp1cmVkID0gYXMuaW50ZWdlcihtb3RvcmlzdHNfaW5qdXJlZCksCiAgICBtb3RvcmlzdHNfa2lsbGVkID0gYXMuaW50ZWdlcihtb3RvcmlzdHNfa2lsbGVkKQogICkKZ2xpbXBzZShkZikKYGBgCgojIyBEQVRBIFFVQUxJVFkgQ0hFQ0tTCgpgYGB7ciBxdWFsaXR5LWNoZWNrc30KIyBWaXN1YWxpemUgbWlzc2luZ25lc3MKdmlzX21pc3MoZGYpCgojIENvdW50IE5BIHZhbHVlcyBwZXIgY29sdW1uCmNvbFN1bXMoaXMubmEoZGYpKQpgYGAKSWRlbnRpZnkgYW5kIHJlbW92ZSA0MjYgcm93cyB3aXRoIGV4dGVuc2l2ZSBtaXNzaW5nbmVzcwoKYGBge3Igcm93cy13aXRoLU5Bc30KZGYkbmFfcmF0ZSA8LSByb3dNZWFucyhpcy5uYShkZikpCgojIEZpbHRlciBvdXQgcm93cyB3aXRoIGhpZ2ggbWlzc2luZ25lc3MKZGYgPC0gZGYgJT4lCiAgICBmaWx0ZXIocm93TWVhbnMoaXMubmEoLikpIDw9IDAuMDUpCgojIERyb3AgMjkgcm93cyB3aXRoIHBvdmVydHlfcmF0ZSBOQSBhbmQvb3IgMzggdW5lbXBsb3ltZW50X3JhdGUgTkEgdmFsdWVzCmRmIDwtIGRmICU+JQogICAgZHJvcF9uYShjKHVuZW1wbG95bWVudF9yYXRlLCBwb3ZlcnR5X3JhdGUpKQoKIyBEcm9wIG5hX3JhdGUgY29sdW1uCmRmIDwtIGRmICU+JSBzZWxlY3QoLW5hX3JhdGUsIC1pbmp1cnlfZmF0YWxpdHlfcmF0aW8pCmBgYAogClNlY29uZCBxdWFsaXR5IGNoZWNrCiAKYGBge3IgcXVhbGl0eS1jaGVjay1hZ2Fpbn0KIyBWaXN1YWxpemUgbWlzc2luZ25lc3MKdmlzX21pc3MoZGYpCmBgYApOTyBOQSB2YWx1ZXMhCgoKIyMgV2luc29yaXphdGlvbiBvZiBleHRyZW1lIHZhbHVlcwoKYGBge3Igd2luc29yaXplLXZhcmlhYmxlc30KcmVwbGFjZV90b3BfOTlfd2l0aF9tZWRpYW4gPC0gZnVuY3Rpb24oeCkgewogICMgRW5zdXJlIG51bWVyaWMKICBpZiAoIWlzLm51bWVyaWMoeCkpIHN0b3AoIkNvbHVtbiBtdXN0IGJlIG51bWVyaWMuIikKICAKICAjIENhbGN1bGF0ZSB0aGUgOTl0aCBwZXJjZW50aWxlIGFuZCBtZWRpYW4KICB1cHBlcl90aHJlc2hvbGQgPC0gcXVhbnRpbGUoeCwgMC45OSwgbmEucm0gPSBUUlVFKQogIG1lZGlhbl92YWwgPC0gbWVkaWFuKHgsIG5hLnJtID0gVFJVRSkKICAKICAjIFJlcGxhY2UgdmFsdWVzIGFib3ZlIHRoZSA5OXRoIHBlcmNlbnRpbGUgd2l0aCB0aGUgbWVkaWFuCiAgeFt4ID4gdXBwZXJfdGhyZXNob2xkXSA8LSBtZWRpYW5fdmFsCiAgcmV0dXJuKHgpCn0KCnBlcl8xMDAwX3ZhcnMgPC0gZ3JlcCgicGVyXzEwMDAiLCBuYW1lcyhkZiksIHZhbHVlID0gVFJVRSkKZGZbcGVyXzEwMDBfdmFyc10gPC0gbGFwcGx5KGRmW3Blcl8xMDAwX3ZhcnNdLCByZXBsYWNlX3RvcF85OV93aXRoX21lZGlhbikKYGBgCgojIyBVbml2YXJpYXRlIEFuYWx5c2lzCgpgYGB7ciB1bml2YXJpYXRlLWFuYWx5c2lzLCBlY2hvPUZBTFNFfQojIElkZW50aWZ5IG51bWVyaWMgY29sdW1ucwpudW1lcmljX3ZhcnMgPC0gZGYgJT4lIAogIHNlbGVjdCh3aGVyZShpcy5udW1lcmljKSkgJT4lIAogICAgc2VsZWN0KC15ZWFyKSAlPiUKICBuYW1lcygpCgojIENyZWF0ZSBoaXN0b2dyYW1zIGFuZCBib3hwbG90cyBmb3IgZWFjaCBudW1lcmljIHZhcmlhYmxlCmZvciAodmFyIGluIG51bWVyaWNfdmFycykgewogICMgSGlzdG9ncmFtCiAgcHJpbnQoCiAgICBnZ3Bsb3QoZGYsIGFlc19zdHJpbmcoeCA9IHZhcikpICsKICAgICAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDMwLCBmaWxsID0gInN0ZWVsYmx1ZSIsIGNvbG9yID0gIndoaXRlIikgKwogICAgICBsYWJzKHRpdGxlID0gcGFzdGUoIkhpc3RvZ3JhbSBvZiIsIHZhciksIHggPSB2YXIsIHkgPSAiQ291bnQiKSArCiAgICAgIHRoZW1lX21pbmltYWwoKQogICkKICAKICAjIEJveHBsb3QKICBwcmludCgKICAgIGdncGxvdChkZiwgYWVzX3N0cmluZyh4ID0gIicnIiwgeSA9IHZhcikpICsKICAgICAgZ2VvbV9ib3hwbG90KGZpbGwgPSAidG9tYXRvIiwgY29sb3IgPSAiYmxhY2siKSArCiAgICAgIGxhYnModGl0bGUgPSBwYXN0ZSgiQm94cGxvdCBvZiIsIHZhciksIHggPSAiIiwgeSA9IHZhcikgKwogICAgICB0aGVtZV9taW5pbWFsKCkKICApCn0KYGBgCgojIyBHUk9VUCBDT1JSRUxBVEVEIFNPQ0lPLUVDT05PTUlDIFZBUklBQkxFUwoKYGBge3IgZ3JvdXAtdmFyc30KbnVtZXJpY192YXJzIDwtIHNhcHBseShkZiwgaXMubnVtZXJpYykKY29yX21hdHJpeCA8LSBjb3IoZGZbICwgbnVtZXJpY192YXJzXSwgCiAgICAgICAgICAgICAgICAgIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiKQoKIyBJZGVudGlmeSBjb2x1bW5zIHRvIGRyb3AgKHRvIHJlZHVjZSBtdWx0aWNvbGxpbmVhcml0eSkKaGlnaF9jb3JyIDwtIGNhcmV0OjpmaW5kQ29ycmVsYXRpb24oY29yX21hdHJpeCwgY3V0b2ZmID0gMC44KQpjb2xuYW1lcyhjb3JfbWF0cml4KVtoaWdoX2NvcnJdCgojIE9wZW4gYSBQTkcgZGV2aWNlCnBuZygiLi4vcmVwb3J0L3Bsb3RzL3BhaXJ3aXNlX2NvcnJlbGF0aW9uX21hdHJpeC5wbmciLCB3aWR0aCA9IDEyMDAsIGhlaWdodCA9IDEwMDAsIHJlcyA9IDMwMCkKCiMgRHJhdyB0aGUgcGxvdApjb3JycGxvdChjb3JfbWF0cml4LCBtZXRob2QgPSAiY29sb3IiLCB0eXBlID0gInVwcGVyIiwgdGwuY2V4ID0gMC41KQoKIyBDbG9zZSB0aGUgZGV2aWNlCmRldi5vZmYoKQpgYGAKIyMgRFJPUCBSRURVTkRBTlQgVkFSSUFCTEVTCgpgYGB7ciBkcm9wLXJlZHVuZGFudH0KZGYgPC0gZGYgJT4lCiAgICBzZWxlY3QoLWMocG92ZXJ0eV9yYXRlLAogICAgICAgICAgICAgIHBjdF9iZWxvd19wb3ZlcnR5LAogICAgICAgICAgICAgIHBjdF9hYm92ZV9wb3ZlcnR5LAogICAgICAgICAgICAgIHBjdF9lbXBsb3llZCwKICAgICAgICAgICAgICBwY3RfdW5lbXBsb3llZCwKICAgICAgICAgICAgICBwY3RfZHJpdmVfYWxvbmUpKQpgYGAKCiMjIEFERCBCT1JPVUdIUwoKYGBge3IgYWRkLWJvcm91Z2hzfQpkZiA8LSBkZiAlPiUKICBtdXRhdGUoCiAgICBib3JvdWdoID0gY2FzZV93aGVuKAogICAgICBzdWJzdHIoZ2VvaWQsIDEsIDUpID09ICIzNjAwNSIgfiAiQnJvbngiLAogICAgICBzdWJzdHIoZ2VvaWQsIDEsIDUpID09ICIzNjA0NyIgfiAiQnJvb2tseW4iLAogICAgICBzdWJzdHIoZ2VvaWQsIDEsIDUpID09ICIzNjA2MSIgfiAiTWFuaGF0dGFuIiwKICAgICAgc3Vic3RyKGdlb2lkLCAxLCA1KSA9PSAiMzYwODEiIH4gIlF1ZWVucyIsCiAgICAgIHN1YnN0cihnZW9pZCwgMSwgNSkgPT0gIjM2MDg1IiB+ICJTdGF0ZW4gSXNsYW5kIiwKICAgICAgVFJVRSB+ICJVbmtub3duIgogICAgKQogICkKCmBgYAoKIyMgRXhwb3J0IGNsZWFuIGRhdGEKCmBgYHtyIGV4cG9ydH0Kc2F2ZVJEUyhkZiwgIi4uL2RhdGEvbW9kZWxzL3NvY2lhbC1yaXNrLWNyYXNoLXJhdGUtZGF0YS5yZHMiKQpgYGA=